package xs.szw.service.service.auth.impl;


import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import xs.szw.common.constant.RedisKeyConstant;

import xs.szw.common.result.ResultCode;
import xs.szw.common.utils.JwtUtil;

import xs.szw.service.config.property.CaptchaProperties;
import xs.szw.service.model.dto.user.UserDto;

import xs.szw.service.enums.CaptchaTypeEnum;
import xs.szw.service.model.pojo.captcha.CaptchaInfo;
import xs.szw.service.model.pojo.security.AuthenticationToken;
import xs.szw.service.model.pojo.security.LoginUser;
import xs.szw.service.service.auth.AuthService;
import xs.szw.service.utils.RedisCache;
import xs.szw.service.utils.SecurityUtils;

import java.awt.*;
import java.util.Objects;
import java.util.concurrent.TimeUnit;



/**
 * @program: My_SpringSecurity
 * @description: 认证中心
 * @author: Songzw
 * @create: 2025-01-31 12:44
 **/
@Service
@Slf4j
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {


    private final AuthenticationManager authenticationManager;

    private final RedisCache redisCache;


    private final CaptchaProperties captchaProperties;


    private final Font font;


    private final CodeGenerator codeGenerator;


    /**
     * 登录
     * @param userDto
     * @return
     */
    public AuthenticationToken login(UserDto userDto) {

        // 请求中的验证码
        String captchaCode = userDto.getCaptchaCode();;
        if(StrUtil.isBlank(captchaCode)){
           throw new RuntimeException("验证码空！");
        }
        //缓存中的验证码
        //1.验证码缓冲部分key uuid
        String verifyCodeKey = userDto.getCaptchaKey();
        //2.redis获取验证码
        String cacheVerifyCode = redisCache.getCacheObject(RedisKeyConstant.CAPTCHA_CODE_PREFIX + verifyCodeKey);
        if (cacheVerifyCode==null){
            throw new RuntimeException("验证码key空！");
        }else {
            // 验证码比对
            if(!codeGenerator.verify(cacheVerifyCode,captchaCode)){
                throw new RuntimeException(ResultCode.USER_VERIFICATION_CODE_ERROR.getMessage());
            }
        }


        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDto.getUsername(),userDto.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        if(Objects.isNull(authenticate)){
            throw new RuntimeException("用户名或密码错误");
        }
        //使用userid生成token
        LoginUser u = (LoginUser) authenticate.getPrincipal();
        String userId = u.getUser().getId().toString();
        String jwt = JwtUtil.createJWT(userId, JSON.toJSONString(u),null);
        Long jwtTtl = JwtUtil.JWT_TTL;
        //authenticate存入redis
        redisCache.setCacheObject(RedisKeyConstant.RBAC_Login_KEY +userId,jwt,jwtTtl.intValue(),TimeUnit.MILLISECONDS);
        //把token响应给前端
//        HashMap<String,String> map = new HashMap<>();
//        map.put("token",jwt);
        //返回AuthenticationToken对象

        Long jwtRefreshTtl = JwtUtil.JWT_REFRESH_TTL;

        AuthenticationToken token = AuthenticationToken.builder()
                .accessToken(jwt)
                .refreshToken("")
                .tokenType("Bearer")
                .expiresIn(jwtTtl.intValue())
                .build();

        return token;
//
    }

    /**
     * 退出
     * @return
     */
    public void logOut() {
        Long userId = SecurityUtils.getLoginUserId();
        redisCache.deleteObject(RedisKeyConstant.RBAC_Login_KEY +userId);
    }

    /**
     * 获取验证码
     * @return
     */
    @Override
    public CaptchaInfo getCaptcha() {
        //1.获取captcha配置对象属性
        //1.1获取配置的验证码类型
        String captchaType = captchaProperties.getType();
        //1.获取配置的验证码宽度
        int width = captchaProperties.getWidth();
        //1.3获取配置的验证码高度
        int height = captchaProperties.getHeight();
        //1.4获取配置的干扰线数量
        int interfereCount = captchaProperties.getInterfereCount();
        //1.5获取配置的验证码字符长度
        int codeLength = captchaProperties.getCode().getLength();

        //2.根据配置的验证码类型创建不同类型的验证码
        AbstractCaptcha captcha;
        if(CaptchaTypeEnum.CIRCLE.name().equalsIgnoreCase(captchaType)){
            captcha = CaptchaUtil.createCircleCaptcha(width,height,codeLength,interfereCount);
        }else if (CaptchaTypeEnum.GIF.name().equalsIgnoreCase(captchaType)){
            captcha = CaptchaUtil.createGifCaptcha(width,height,codeLength);
        }else if(CaptchaTypeEnum.LINE.name().equalsIgnoreCase(captchaType)){
            captcha = CaptchaUtil.createLineCaptcha(width,height,codeLength,interfereCount);
        }else if(CaptchaTypeEnum.SHEAR.name().equalsIgnoreCase(captchaType)){
            captcha = CaptchaUtil.createShearCaptcha(width,height,codeLength,interfereCount);
        }else {
            throw new IllegalArgumentException("Invalid captcha type: " + captchaType);
        }
        // 设置验证码字符生成器
        captcha.setGenerator(codeGenerator);
        // 设置验证码字符透明度
        captcha.setTextAlpha(captchaProperties.getTextAlpha());
        // 设置验证码字符字体
        captcha.setFont(font);

        // 获取生成的验证码字符
        String captchaCode = captcha.getCode();
        // 获取生成的验证码图片的Base64格式数据
        String imageBase64Data = captcha.getImageBase64Data();

        // 验证码文本缓存至Redis，用于登录校验 UUID作为验证码键
        String captchaKey = IdUtil.fastSimpleUUID();
        // 将验证码字符和键存入Redis中，并设置过期时间
        redisCache.setCacheObject(RedisKeyConstant.CAPTCHA_CODE_PREFIX + captchaKey,captchaCode,
                captchaProperties.getExpireSeconds().intValue(),TimeUnit.SECONDS);

        CaptchaInfo captchaInfo = CaptchaInfo.builder()
                .captchaKey(captchaKey)
                .captchaBase64(imageBase64Data)
                .build();
        return captchaInfo;
    }

}
